package com.contractlock.server.controller;

import com.contractlock.server.entity.StoredFile;
import com.contractlock.server.service.IBaseService;
import com.contractlock.server.util.Constants;
import com.contractlock.server.util.DateUtil;
import lombok.Cleanup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.util.*;

/**
 * copyright(c)2021 YYB.ALL rights Reserved
 * <p>
 * 描述:storedFile的controller层
 *
 * @author 原玉波
 * @version 1.0
 * @date 2021/10/19
 */
@Controller
@CrossOrigin
@RequestMapping("/storedFile")
public class StoredFileController {

    //引入slf4j日志对象
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    //注入storedFileService
    @Resource(name = "storedFileService")
    IBaseService<StoredFile> storedFileIService;


    /**
     * 上传接口1, 该接口以MultipartFile入参，需要multipart/form-data格式的请求，postman测试无问题，client端无法调用
     *
     * @param request
     * @param file
     * @return uuid
     */
    @PostMapping("/upload")
    @ResponseBody
    public String upload(HttpServletRequest request, HttpServletResponse response, MultipartFile file) {
        logger.debug("enter storedFile upload method");

        //获取uuid
        String uuid;
        uuid = UUID.randomUUID().toString();
        logger.debug("file UUID=" + uuid);

        /*获取原始文件名称*/
        String originalFilename = file.getOriginalFilename();
        logger.debug("file originalName=" + originalFilename);

        //替换文件名为uuid
        String fileName = uuid;

        //获取文件大小
        long size = file.getSize();
        logger.debug("file size=" + size);

        //获取文件类型
        String[] strArray = originalFilename.split("\\.");
        int suffixIndex = strArray.length - 1;
        String type = "." + strArray[suffixIndex];
        logger.debug("file type=" + type);

        //创建时间
        Date createTime = new Date();
        String createTimeStr = DateUtil.dateToString(createTime);

        //指定存放目录，为yyMMdd的目录
        String path = "D:\\AAA_Cpp\\MyProject\\ContractLock" + "\\" + createTimeStr;
        logger.debug(path);
        File pathFile = new File(path);
        if (!pathFile.exists()) {
            /*如果上传目录不存在，则创建*/
            pathFile.mkdirs();
        }

        //存放路径
        String url = path + File.separator + fileName + type;

        boolean result = false;
        try {
            //上传文件到指定位置
            file.transferTo(new File(url));
            logger.debug(url);

            //给storedFile设置各个属性
            StoredFile storedFile = new StoredFile();
            storedFile.setSize(size);
            storedFile.setType(type);
            storedFile.setOriginalName(originalFilename);
            storedFile.setCreateTime(createTime);
            storedFile.setUrl(url);
            storedFile.setUuid(uuid);

            //存入数据库
            result = storedFileIService.add(storedFile);
        } catch (IOException e) {
            logger.error("上传失败", e);
        }
        if (!result) {
            uuid = "上传失败";
            logger.error("数据库元数据存放错误，上传失败");
        }
        return uuid;
    }

    /**
     * 上传接口2，不使用multiPartFile，可以正常使用
     *
     * @param request
     * @param response
     * @return uuid
     * @throws Exception
     */
    @PostMapping("/upload2")
    @ResponseBody
    public String FileUploadServer(HttpServletRequest request, HttpServletResponse response) throws Exception {

        logger.debug("enter StoredFile upload2 method");
        String uuid;
        uuid = UUID.randomUUID().toString();
        logger.debug("file UUID=" + uuid);
        //文件大小
        Long size = Long.valueOf(request.getHeader("size"));
        logger.debug("file size=" + size);
        //文件类型
        String type = request.getHeader("type");
        logger.debug("file type=" + type);
        //原始文件名
        String originalFilename = URLDecoder.decode(request.getHeader("name"), "UTF-8");
        logger.debug("file originalFilename=" + originalFilename);

        //指定创建时间，该时间为服务器接收到数据的时间
        Date time = new Date();
        String createTimeStr = DateUtil.dateToString(time);
        logger.debug("file createTimeStr=" + createTimeStr);

        //指定存放目录，为yyMMdd的目录
        String path = "D:\\AAA_Cpp\\MyProject\\ContractLock\\uploadFile" + "\\" + createTimeStr;
        logger.debug(path);

        File pathFile = new File(path);
        if (!pathFile.exists()) {
            //如果上传目录不存在，则创建
            pathFile.mkdirs();
        }

        //文件存放路径
        String url = path + File.separator + uuid + type;
        logger.debug(url);

        InputStream is = request.getInputStream();
        File newFile = new File(url);
        FileOutputStream fos = new FileOutputStream(newFile);
        byte[] b = new byte[2048];
        int length = 0;
        while ((length = is.read(b)) != Constants.END) {
            fos.write(b, 0, length);
        }

        //创建StoredFile对象，设置属性
        StoredFile storedFile = new StoredFile();
        storedFile.setSize(size);
        storedFile.setType(type);
        storedFile.setOriginalName(originalFilename);
        storedFile.setCreateTime(time);
        storedFile.setUrl(url);
        storedFile.setUuid(uuid);
        logger.debug("storedFile=" + storedFile.toString());

        //将元数据存入数据库
        boolean result = storedFileIService.add(storedFile);
        if (!result) {
            uuid = "upload fail";
            logger.error("数据库元数据存放错误，上传失败");
        }
        is.close();
        fos.close();
        return uuid;
    }

    /**
     * 下载接口
     *
     * @param uuid
     * @param response
     * @param request
     * @throws IOException
     */
    @GetMapping("/download")
    public void download(String uuid
            , HttpServletResponse response, HttpServletRequest request) throws IOException {

        logger.debug("enter download method");
        logger.debug("uuid=" + uuid);

        //按照uuid的条件去查询storedFile的List（uuid唯一，故一般只有一条信息或者不存在
        Map<String, Object> conditions = new HashMap<>();
        conditions.put("uuid", uuid);
        List<StoredFile> storedFileList = storedFileIService.search(conditions);
        logger.debug(storedFileList.toString());

        //判断该uuid对应的文件是否存在
        if (storedFileList.size() != Constants.EXIST) {
            //不存在，响应401状态码
            response.setStatus(410);
            logger.debug("file is not exist");
            logger.debug(response.getStatus() + "");
        } else {

            //获取存放路径和原始文件名
            StoredFile storedFile = storedFileList.get(0);
            String path = storedFile.getUrl();
            String originalName = storedFile.getOriginalName();
            String type = storedFile.getType();

            logger.debug("path=" + path);
            //文件名设置编码，防止乱码
            String fileName = new String(originalName.getBytes("UTF-8"), "ISO-8859-1");
            //设置好请求头中的文件名，在下载的时候可以得到正确的文件名，但是使用postman测试，文件名会变成response
            response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
            response.setHeader("type", type);
            response.setHeader("originalName", originalName);
            logger.debug(response.getHeader("Content-Disposition"));

            //lombook的注解，相当于finally
            @Cleanup
            BufferedInputStream is =
                    new BufferedInputStream(new FileInputStream(path));
            BufferedOutputStream os =
                    new BufferedOutputStream(response.getOutputStream());
            byte[] b = new byte[2048];
            int length = 0;
            //读入缓冲区的总字节数，如果由于已到达流末尾而没有更多数据，则为-1 。
            while ((length = is.read(b)) != Constants.END) {
                os.write(b, 0, length);
            }
            //清空缓冲，刷新缓存
            os.flush();
        }

    }

    /**
     * 获取元数据接口
     *
     * @param uuid
     * @return 元数据的json
     */
    @GetMapping("/getInfo")
    @ResponseBody
    public StoredFile getInfo(String uuid) {
        logger.debug("enter StoredFile method");
        logger.debug("uuid=" + uuid);

        //按照uuid条件查询
        Map<String, Object> conditions = new HashMap<>();
        conditions.put("uuid", uuid);
        List<StoredFile> storedFileList = storedFileIService.search(conditions);
        logger.debug(storedFileList.toString());

        //判断对应的文件元数据是否存在
        if (storedFileList.size() == Constants.EXIST) {
            logger.debug(storedFileList.get(0).toString());
            return storedFileList.get(0);
        } else {
            logger.debug("file is not exist");
            return null;
        }
    }


}
